package com.cory.utils.service;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.mail.Address;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import lombok.extern.slf4j.Slf4j;
import com.cory.utils.file.PropertiesUtils;

/**
 * @author xc
 * @version 2016-10-25
 */
@Slf4j
public class Mail {
	public static final String CHARSET_DEFUALT = "UTF-8";
	
	private static Properties props = new Properties();
	
	/**
	 * 属性文件加载对象
	 */
	private static PropertiesUtils loader = new PropertiesUtils("conf/mail.properties");
	
	static {
		props.setProperty("mail.smtp.socketFactory.class", loader.getProperty("mail.smtp.socketFactory.class"));
        props.setProperty("mail.smtp.socketFactory.fallback",loader.getProperty("mail.smtp.socketFactory.fallback"));
        props.setProperty("mail.store.protocol", loader.getProperty("mail.store.protocol")); 
        props.setProperty("mail.smtp.host", loader.getProperty("mail.smtp.host")); 
        props.setProperty("mail.smtp.port", loader.getProperty("mail.smtp.port"));
        props.setProperty("mail.smtp.socketFactory.port", loader.getProperty("mail.smtp.socketFactory.port"));
        props.put("mail.smtp.auth", loader.getProperty("mail.smtp.auth"));
	}
	
	private String userName;
	private String password;
	private Session mailSession;
	
	public Mail() {
		this.userName = loader.getProperty("mail.default.userName");
		this.password = loader.getProperty("mail.default.password");
		init();
	}
	
	public Mail(String userName,String password) {
		this.userName = userName;
		this.password = password;
		init();
	}
	
	private void init() {
		mailSession = Session.getInstance(props, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(userName, password);
            }
        });
	}
	
	/**
	 * 邮件发送：收件人
	 */
	public Boolean send(String to, String subject, String content) {
		return send(to, null, null, subject, content);
	}
	
	/**
	 * 邮件发送：收件人，抄送
	 */
	public Boolean send(String to, String cc, String subject, String content) {
		return send(to, cc, null, subject, content);
	}
	
	/**
	 * 邮件发送：收件人，抄送，密送
	 */
	public Boolean send(String to, String cc, String bcc, String subject, String content) {
		try {
			return send(toMailAddress(to), toMailAddress(cc), toMailAddress(bcc), subject, content);
		} catch(AddressException e) {
			log.error("toMailAddress {} {} {}", to, cc, bcc, e);
			return false;
		}
	}
	
	private Boolean send(Address[] to,Address[] cc,Address[] bcc,String subject, String content){
		if(mailSession == null) {
			log.error("FROM ADDRESS IS ERROR");
			return false;
		}
		
		if(to == null || to.length == 0) {
			log.error("TO ADDRESS IS ERROR");
			return false;
		}
		
		try {
			Message message = new MimeMessage(mailSession);
			message.setHeader("Content-Transfer-Encoding",
					CHARSET_DEFUALT);
			message.setSentDate(new Date());
			message.setFrom(toMailFormat(userName));// 发件人
			message.addRecipients(Message.RecipientType.TO, to);
			if (cc != null) {
				message.addRecipients(Message.RecipientType.CC, cc);
			}
			if (bcc != null) {
				message.addRecipients(Message.RecipientType.BCC, bcc);
			}
			message.setSubject(MimeUtility.encodeText(subject, "utf-8", null));
			message.setText(content);
			MimeBodyPart bodyPart = new MimeBodyPart();
			bodyPart.setContent(content, "text/html;charSet="
					+ CHARSET_DEFUALT);
			MimeMultipart multiPart = new MimeMultipart();
			multiPart.addBodyPart(bodyPart);
			message.setContent(multiPart);
			message.saveChanges();
	
			Transport.send(message);
			return true;
		} catch(MessagingException e) {
			log.error("send error", e);
		} catch(UnsupportedEncodingException e) {
			log.error("encode text {}", subject, e);
		}
		return false;
	}
	
	private static boolean isMailAddress(String mailAddress) {
		if (mailAddress == null || mailAddress.length() < 5) {
			return false;
		}
		String regex = "\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(mailAddress);
		return m.matches();
	}
	
	private static InternetAddress toMailFormat(String str)
			throws AddressException {
		if (isMailAddress(str)) {
			return new InternetAddress(str.trim());
		}  else {
			return null;
		}
	}
	
	private static Address[] toMailAddress(String str) throws AddressException {
		StringTokenizer s = getPartStr(str, null);
		Address[] ads = null;
		List<InternetAddress> mailList = null;
		if (s != null) {
			mailList = new ArrayList<InternetAddress>();
			while (s.hasMoreTokens()) {
				String sn = s.nextToken();
				InternetAddress ia = toMailFormat(sn);
				if (ia != null) {
					mailList.add(ia);
				}
			}
		}
		if (mailList != null && mailList.size() > 0) {
			ads = new Address[mailList.size()];
			for (int i = 0; i < mailList.size(); i++) {
				InternetAddress ia = mailList.get(i);
				ads[i] = ia;
			}
		}
		return ads;
	}
	
	private static StringTokenizer getPartStr(String str, String separatedStr) {
		if(str == null || str.length() == 0) return null;
		
		StringTokenizer s;
		if (separatedStr == null || separatedStr.length() == 0) {
			if (str.indexOf(";") > 0)
				s = new StringTokenizer(str, ";");
			else
				s = new StringTokenizer(str, ",");
		} else {
			s = new StringTokenizer(str, separatedStr);
		}
		return s;
	}
	
}
